<template>
  <div class="menu-tree">
    <div class="py-3">
      <div class="flex">
        <n-button ghost icon-placement="left" @click="packHandleFn">
          {{ $t(`role.table.${defaultExpandAll ? 'fold' : 'showAll'}`) }}
        </n-button>

        <n-button ghost icon-placement="left" @click="checkedAllHandleFn" style="margin-left: 12px">
          {{ $t(`role.table.${checkedKeys.length ? 'selectNone' : 'selectAll'}`) }}
        </n-button>

        <div class="menu-tree-search flex" style="margin-left: auto">
          <div>
            <n-input v-model:value="pattern" :placeholder="$t('common.form.placeKeyWord')">
              <template #suffix>
                <n-icon size="18" class="cursor-pointer">
                  <SearchOutlined />
                </n-icon>
              </template>
            </n-input>
          </div>
        </div>
      </div>
    </div>

    <div class="menu-tree-view">
      <n-tree
        ref="treeRef"
        :show-irrelevant-nodes="false"
        :pattern="pattern"
        :data="treeData"
        block-line
        :cascade="false"
        checkable
        :virtual-scroll="true"
        :label-field="labelField"
        :key-field="'menuCode'"
        :default-expand-all="defaultExpandAll"
        :checked-keys="checkedKeys"
        :indeterminate-keys="indeterminateKeys"
        @update:checked-keys="checkedTreeFn"
        @update:expanded-keys="onExpandedKeysFn"
      />
      <div class="after">
        <n-empty :description="$t('common.table.noData')">
          <template #icon>
            <img src="@/assets/svg/empty.svg" />
          </template>
        </n-empty>
      </div>
    </div>
  </div>
</template>

<script lang="ts" setup name="RoleMenuTree">
  import { useUserStoreWidthOut } from '@/store/modules/user';
  import { useMixins } from '@/hooks/useMixins';
  import { SearchOutlined } from '@vicons/antd';

  const userStore = useUserStoreWidthOut();

  const { info = {} } = userStore;

  const { menuList = [] } = info;

  const { cloneDeep, language, t } = useMixins();

  const expandedKeys = ref([]);

  const checkedKeys: any = ref([]);

  const indeterminateKeys: any = ref([]);

  const treeData = ref([]);

  const treeRef: any = ref(null);

  const defaultExpandAll = ref(true);

  const allPermissions = ref([]);

  const oldCheckedKeys: any = ref([]);

  const pattern = ref('');

  const labelField = computed(() => (language.value === 'zh' ? 'menuNameZh' : 'menuNameEn'));

  const getAllPermissionsFn = (menuList = [], list = []) => {
    if (menuList && menuList.length) {
      for (const item of menuList) {
        const { menuCode = '', children = [] } = item;

        if (menuCode) {
          list.push(menuCode || '');
        }

        if (children && children.length) {
          getAllPermissionsFn(children, list);
        }
      }
    }

    return list;
  };

  const setMenuListFn: any = (list, level = 1) => {
    const newList: any = [];

    list.forEach((item) => {
      const newItem = cloneDeep(item);

      newItem.level = level;

      if (item.menuType === 0 || item.menuType === 1) {
        newItem.menuName =
          language.value === 'zh'
            ? item.menuNameZh || item.menuNameEn || ''
            : item.menuNameEn || item.menuNameZh || '';

        if (item.children && item.children.length) {
          newItem.children = setMenuListFn(item.children, level + 1);
        }

        newList.push(newItem);
      } else if (item.menuType === 2) {
        newItem.menuNameZh = `[${t('common.button.btn')}]${item.menuNameZh}`;

        newList.push(newItem);
      }
    });

    return newList;
  };

treeData.value = setMenuListFn(cloneDeep(menuList));

// console.log(treeData.value)

  allPermissions.value = getAllPermissionsFn(cloneDeep(menuList));

  const packHandleFn = () => {
    defaultExpandAll.value = !defaultExpandAll.value;
  };

  const checkedAllHandleFn = () => {
    indeterminateKeys.value = [];

    if (!checkedKeys.value.length) {
      checkedKeys.value = toRaw(allPermissions.value);
    } else {
      checkedKeys.value = [];
    }
  };

  const checkedTreeFn = (keys, _options) => {
    checkedKeys.value = [...keys];

    setTreeStatusFn();
  };

  const onExpandedKeysFn = (keys) => {
    expandedKeys.value = keys;
  };

  const setTreeStatusFn = () => {
    const checkedList = toRaw(checkedKeys.value);

    const oldCheckedKeysList = toRaw(oldCheckedKeys.value);

    const computedList = getArrDifferenceFn(checkedList, oldCheckedKeysList);

    if (computedList) {
      let newCheckedList = [...checkedList];

      for (const item of computedList) {
        const obj: any = findMenuFn(item);

        if (obj) {
          const { parentMenuId = null, children = [], menuCode = null } = obj;

          let allChildMenuCodeList: any = [];

          if (children && children.length) {
            allChildMenuCodeList = [...findAllChildMenuCodeFn(children)];
          }

          if (checkedList.length > oldCheckedKeysList.length) {
            // 勾选
            if (menuCode) {
              newCheckedList = [...newCheckedList, menuCode];
            }

            if (parentMenuId) {
              newCheckedList = [...newCheckedList, ...findAllParentMenuCodeFn(parentMenuId)];

              // console.log(newCheckedList);
            }

            if (allChildMenuCodeList.length) {
              newCheckedList = [...newCheckedList, ...allChildMenuCodeList];
            }
          } else {
            // 不勾选
            // console.log(allChildMenuCodeList);
            // console.log(newCheckedList);
            if (allChildMenuCodeList.length) {
              for (const aItem of allChildMenuCodeList) {
                const index = newCheckedList.indexOf(aItem);

                if (index !== -1) {
                  newCheckedList.splice(index, 1);
                }
              }
            }
          }
        }
      }

      newCheckedList = Array.from(new Set(newCheckedList));

      const indeterminateKeysList = setIndeterminateKeysFn(newCheckedList);

      // console.log(indeterminateKeysList);

      checkedKeys.value = newCheckedList;

      oldCheckedKeys.value = cloneDeep(newCheckedList);

      indeterminateKeys.value = Array.from(new Set(indeterminateKeysList));
    }

    // oldCheckedKeys.value = cloneDeep(checkedList);
  };

  const findMenuFn = (code = '', type = 'menuCode', list = toRaw(treeData.value)) => {
    // 查找对应的资源
    if (!['', undefined, null].includes(code) && list && list.length) {
      let obj = null;

      list.every((item) => {
        const { children = [] } = item;

        if (item[type] === code) {
          obj = item;

          return false;
        }

        if (!obj && children && children.length) {
          obj = findMenuFn(code, type, children);
        }

        return true;
      });

      return obj;
    }

    return null;
  };

  const findAllParentMenuCodeFn = (pid, list: any = []) => {
    // 查找所有父级资源
    if (!['', undefined, null].includes(pid)) {
      const obj: any = findMenuFn(pid, 'menuId');

      // console.log(obj);

      if (obj) {
        const { menuCode = null, parentMenuId } = obj;

        list.push(menuCode);

        findAllParentMenuCodeFn(parentMenuId, list);
      }
    }

    return list;
  };

  const findAllChildMenuCodeFn = (children = [], list: any = []) => {
    if (children && children.length) {
      for (const item of children) {
        const { menuCode = null, children: child = [] } = item;

        if (menuCode) {
          list.push(menuCode);
        }

        if (child && child.length) {
          findAllChildMenuCodeFn(child, list);
        }
      }
    }

    return list;
  };

  const getArrDifferenceFn = (arr1, arr2) => {
    return arr1.concat(arr2).filter((v, _i, arr) => {
      return arr.indexOf(v) === arr.lastIndexOf(v);
    });
  };

  const setIndeterminateKeysFn = (checkedList: any = [], indeterminateKeysList: any = []) => {
    if (checkedList && checkedList.length) {
      const isReturn = checkedList.every((item) => {
        const obj = findMenuFn(item);

        if (obj) {
          const { children = [] as any, menuCode = '', level = 0, parentMenuId = null, menuType } = obj;

          if (children && children.length) {
            const childCheckedList: any = [];

            let hasButton = false;

            for (const cItem of children) {
              if (cItem.menuType === 2) {
                hasButton = true;
              }

              if (checkedList.includes(cItem.menuCode)) {
                childCheckedList.push(cItem.menuCode);
              }
            }

            if (childCheckedList.length !== children.length) {
              if (childCheckedList.length || hasButton || (level > 3 && menuType !== 0)) {
                indeterminateKeysList.push(...[menuCode, ...findAllParentMenuCodeFn(parentMenuId)]);
              } else {
                const index = checkedList.indexOf(item);

                if (index !== -1) {
                  checkedList.splice(index, 1);

                  return false;
                }
              }
            }
          }
        }

        return true;
      });

      if (!isReturn) {
        return setIndeterminateKeysFn(checkedList);
      } else {
        // console.log(indeterminateKeysList);
        return indeterminateKeysList;
      }
    }
  };

  const setPermissionCodeListFn = (permissionCodeList = []) => {
    if (permissionCodeList && permissionCodeList.length) {
      oldCheckedKeys.value = [...permissionCodeList];

      checkedKeys.value = [...permissionCodeList];

      setTreeStatusFn();
    } else {
      checkedKeys.value = [];

      indeterminateKeys.value = [];
    }
  };

  const getPermissionCodeListFn = () => {
    return checkedKeys.value;
  };

  defineExpose({ setPermissionCodeListFn, getPermissionCodeListFn });
</script>
